/*
 * tvwidget
 * A HTML widget for displaying phylogenetic trees
 * Copyright (C) 2008 Roderic D. M. Page <r.page@bio.gla.ac.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307, USA.
 */

#ifdef __BORLANDC__
	// Undefine __MINMAX_DEFINED so that min and max are correctly defined
	#ifdef __MINMAX_DEFINED
		#undef __MINMAX_DEFINED
	#endif
    // Ignore "Cannot create precompiled header: code in header" message
    // generated when compiling string.cc
    #pragma warn -pch
#endif

#include <string>

// Modified SQUID code to handle command line options
#include "getoptions.h"
#define FILENAME_SIZE 256		// Maximum file name length

// Program options
static struct opt_s OPTIONS[] = {	
	{ "-v", true, ARG_NONE },
	{ "-i", true, ARG_NONE },
	{ "-s", true, ARG_INT },	
	{ "-f", true, ARG_INT },	
	{ "-w", true, ARG_INT },	
	{ "-o", true, ARG_STRING },	
	{ "-r", true, ARG_STRING },	
	{ "-b", true, ARG_STRING },	
	{ "-h", true, ARG_INT }	

};
#define NOPTIONS (sizeof(OPTIONS) / sizeof(struct opt_s))

static char usage[] = "\
Usage: tree2Image [-options] <tree-file> \n\
\n\
  Available options: \n\
     -v:             show version information\n\
     -i:             show internal node labels\n\
     -s: n           tree style (1 = angle, 2 = rectangle, 3 = phylogram\n\
     -o: path        output path (folder where images and js files written\n\
     -r: url         base url for shared css and js\n\
     -b: url         base url for output (URL version of -o)\n\
     -w: n           width of drawing\n\
     -h: n           height of drawing\n\
";

#include <queue>
#include <stack>

#include "gport.h"
#include "TreeLib.h"
#include "lcaquery.h"
#include "nodeiterator.h"
#include "profile.h"
#include "treeorder.h"
#include "treedrawer.h"

std::map <NodePtr, bool> drawInternal;
std::map <NodePtr, int> colourIndex;


void make_internal_list(Tree &t, TreeDrawer *td, int unit=10);
void draw_internals(TreeDrawer *td,  bool showLabel = true);
int interpolate(int pBegin, int pEnd, int pStep, int pMax);

int interpolate(int pBegin, int pEnd, int pStep, int pMax) 
{
	double r = (double)pStep/(double)pMax;
	
	if (pBegin < pEnd) 
	{
  		return ((pEnd - pBegin) * r) + pBegin;
	} 
	else 
	{
  		return ((pBegin - pEnd) * (1 - r)) + pEnd;
	}
}

void make_internal_list(Tree &t, TreeDrawer *td, int unit)
{
	point curPt, lastPt;
	int count = 0;

	lastPt.x = 0.0;
	lastPt.y = -1.0;

	int bottom = -1;

	// Visit tree in postorder (this is important to ensure that we only
	// draw internal node labels for nodes close to the tips of the tree).
	NodeIterator <Node> n (t.GetRoot());
	Node *q = n.begin();
	while (q)
	{
		if (q->IsLeaf()) 
		{
		}
		else
		{	
			// For internal nodes that have a label we draw a vertical line and
			// the internal label. We only want a single column of lines, so
			// we draw the internal node "closest" to the leaves.
			drawInternal[q] = false;
			
			if (q->GetLabel() != "")
			{
				// To do, check that label is not a measure of support, otherwise
				// we will have hundred of extraneous labels
			
				// Internal node span
				NodePtr left;
				NodePtr right;

				q->GetSpan(left, right);

				point L, R, Q;
				L = td->GetCoordinates(left);
				R = td->GetCoordinates(right);
				Q = td->GetCoordinates(q);
				
				// Only draw vertical line if the span of this node doesn't overlap
				// with that of the previously drawn node, and the line would be
				// one unit separate from the previous line. 
				if ((L.y > bottom) && (R.y - L.y > unit))
				{
					// we will draw this internal node
					drawInternal[q]=true;
					
					//Store order of occurrence 
					colourIndex[q] = count;
					count++;
					
					bottom = R.y;
				}
			}
		}
		q = n.next();
	}	
	
	
	
	
}


void draw_internals(TreeDrawer *td, bool showLabel)
{
	// Colours
	
	// 88 = 136
	// 66 = 102
	
//	GBaseColour startColour(0, 153, 102);
//	GBaseColour endColour(102, 255, 204);
//	GBaseColour startColour(204, 0, 0);
//	GBaseColour endColour(0, 0, 255);
	GBaseColour startColour(0, 136, 102);
	GBaseColour endColour(102, 255, 204);
	

	// Iterate over list
	std::map <NodePtr, bool>::iterator it = drawInternal.begin();
	std::map <NodePtr, bool>::iterator end = drawInternal.end();
	while (it != end)
	{
		if ((*it).second)
		{
			NodePtr q = (*it).first;
			
			// Internal node span
			NodePtr left;
			NodePtr right;

			q->GetSpan(left, right);

			point L, R, Q;
			L = td->GetCoordinates(left);
			R = td->GetCoordinates(right);
			Q = td->GetCoordinates(q);
			
			GRect iRect(Q.x, L.y, L.x, R.y);
			
			// interpolation
			int theR = interpolate(startColour.GetR(), endColour.GetR(), colourIndex[q], colourIndex.size());
			int theG = interpolate(startColour.GetG(), endColour.GetG(), colourIndex[q], colourIndex.size());
			int theB = interpolate(startColour.GetB(), endColour.GetB(), colourIndex[q], colourIndex.size());
			
			GBaseColour c(theR, theG, theB);
			Port->SetFillColour(c);
			Port->DrawRect(iRect);
			
			if (showLabel)
			{
				Port->SetFillColour(GBaseColour(128,128,128));
				Port->DrawText(0, (int)(L.y + (R.y - L.y)/2.0), q->GetLabel().c_str());
			}
		}
		it++;
	}
}

//------------------------------------------------------------------------------
int main (int argc, char * argv[])
{
	// Parse options
	// Heavily borrowed from the squid library
	char *optname;
	char *optarg;
	int   optind;

	//default settings for drawing tree
	int width			= 300;
	int height			= 400;
	bool showInternals	= false;
	int treestyle		= 2;
	char file_name[FILENAME_SIZE];
	char base_file_name[FILENAME_SIZE];
	
	// Output path for images and Javascript code for this ree
	char output_path[FILENAME_SIZE] = "";
	
	// URL for output (output_path is a file path, this is a web URL)
	char output_url[FILENAME_SIZE] = "/~rpage/tvtest/";
	
	// Base URL for shared CSS, images, and Javascript 
	char base_url[FILENAME_SIZE] = "http://localhost/~rpage/tvwidget/";

	char thumbnail_file_name[FILENAME_SIZE];
	char js_file_name[FILENAME_SIZE];
	std::string image_files;

	// Get options from command line
	while (Getopt(argc, argv, OPTIONS, NOPTIONS, usage, &optind, &optname, &optarg))
	{
		if (strcmp(optname, "-s") == 0)
		{
			treestyle = atoi(optarg);
		}
		if (strcmp(optname, "-w") == 0)
		{
			width = atoi(optarg);
		}
		if (strcmp(optname, "-h") == 0)
		{
			height = atoi(optarg);
		}
		if (strcmp(optname, "-o") == 0)
		{
			strcpy(output_path,optarg);
		}
		if (strcmp(optname, "-r") == 0)
		{
			strcpy(base_url,optarg);
		}
		if (strcmp(optname, "-b") == 0)
		{
			strcpy(output_url,optarg);
		}

		if (strcmp(optname, "-i") == 0) {  showInternals = true; }
		else if (strcmp(optname, "-v") == 0)
		{
			cout << "tree2Image version 0.1" << endl;
			exit(EXIT_SUCCESS);
		}
	}

	if (argc - optind != 1)
	{
		cerr << "Incorrect number of arguments:" << usage << endl;
		exit (0);
	}
	
	// Ensure any URLs and paths are terminated correctly
	int len = strlen(base_url);
	if (base_url[len-1] != '/')
	{
		strcat(base_url, "/");
	}
	
	len = strlen(output_url);
	if (output_url[len-1] != '/')
	{
		strcat(output_url, "/");
	}
	
	
	// Where we write the images, etc.
	len = strlen(output_path);
	if (len > 0)
	{
		if (output_path[len-1] != '/')
		{
			strcat(output_path, "/");
		}
	}
	
	cout << base_url << endl;
	

	char fname[FILENAME_SIZE];
	strcpy( fname, argv[optind++] );
	
	// Base file name (no path)
	int pos = strlen(fname);
	pos--;
	while (pos > -1)
	{
		if (fname[pos] == '/') break;
		pos--;
	}
	if (pos < 0)
	{
		strcpy(base_file_name, fname);
	}
	else
	{
		strcpy(base_file_name, fname + pos + 1);
	}

	// Check file exists
	FILE* file = fopen( fname, "r" );
	if( file != NULL )
	{
		fclose(file);
		file = NULL;
	}
	else
	{
		cerr << "File \"" << fname << "\" does not exist." << endl;
		exit (1);
 	}

	//--------------------------------------------------------------------------
	// OK, let's read in a set of trees from a file and get the first tree 
	ifstream f;
	
	// A profile is a set of trees. This is a template class, so we can
	// have a set of trees of class Tree, or any of its descendants.
	Profile<Tree> p;

	f.open (fname);
	if (!p.ReadTrees (f))
	{
		cout << "Failed to read trees" << endl;
		exit(1);
	}
	f.close ();
	
	// Get the first tree in the profile
	Tree t = p.GetIthTree(0);

	t.Update();
	t.MakeNodeList();
	
	// Make the tree look nice by ordering it
    RightOrder ta (&t);
    ta.Order();
	
	int fontHeight = 9;
	
	//--------------------------------------------------------------------------
	// Make a full size tree image	
	
	// Height
	int h = t.GetNumLeaves() * (fontHeight + 1);
	
	// Clear internal node depths
	for (int i = t.GetNumLeaves(); i < t.GetNumNodes(); i++)
	{
		t[i]->SetDepth(0);
	}
	// Compute maximum depth of tree
	int maxDepth = 0;
	for (int i = 0; i < t.GetNumLeaves();  i++)
	{
		NodePtr p = t[i]->GetAnc();
		int count = 1;
		while (p)
		{
			if (count > p->GetDepth())
			{
				p->SetDepth(count);
				if (count > maxDepth)
					maxDepth = count;
			}
			count++;
			p = p->GetAnc();
		}
	}
	// w is the width of the tree drawing (excluding labels)
	// Ideally the horizontal space between each node is the
	// same as the vertical gap between each leaf. 
	int w = maxDepth * fontHeight;
	
	// Find the label length
	
	// For pixel font we need exact widths for each character in order to
	// compute the lenght of the string when drawn.
	int maxLabelLength = 0;
	for (int i = 0; i < t.GetNumLeaves(); i++)
	{
		std::string s = t[i]->GetLabel();
		
		int len = s.length();
		int strWidth = 0;
		for (int j = 0; j < len; j++)
		{
			char c = s[j];
			int charWidth = 0;
			 if (islower(c))
			 {
				switch (c)
				{
					case 'i':
					case 'l':
						charWidth = 3;
						break;
						
					case 'j':
						charWidth = 4;
						break;

					case 'm':
					case 'w':
						charWidth = 9;
						break;

					case 'v':
					case 'x':
					case 'z':
						charWidth = 7;
						break;
					
					default:
						charWidth = 6;
						break;
				}
			 }
			 if (isupper(c))
			 {
				switch (c)
				{							
					case 'i':
						charWidth = 3;
						break;
					
					case 'm':
					case 'w':
						charWidth = 9;
						break;
					
					default:
						charWidth = 7;
						break;
				}
			 }
			 if (isdigit(c))
			 {
				charWidth = 7;
			 }
			 if (isspace(c))
			 {
				charWidth = 3;
			}
			if (ispunct(c))
			{
				switch (c)
				{
					case '.':
					case ':':
					case '\'':
						charWidth = 2;
						break;

					case ',':
					case ';':
						charWidth = 4;
						break;
												
					case '{':
					case '}':
						charWidth = 7;
						break;
					
					case '(':
					case ')':
					case '"':
					case '-':
					case '_':
						charWidth = 5;
						break;
						
					// just in case
					default:
						charWidth = 5;
						break;
				}
			
			}
			 strWidth += charWidth;
		}
		
		//cout << s << " " << strWidth << endl;
		
		if (strWidth > maxLabelLength)  { maxLabelLength = strWidth; }
	}
	
	// Ensure we have space for tree and labels
	int labelSpace  = maxLabelLength;			
	int diff = w + labelSpace - width;	
	
	if (diff > 0)
	{
		// we can't fit tree with internal node gap of fontHeight, 
		// and the full leaf labels as is
		
		// 1. can we shrink the tree?
		//int originalW = w;
		
		// squash tree by amount of extra space needed for the labels
		w -= diff;
		
		if (w < (2 * maxDepth))
		{
			// Houston we have a problem, if we get here need to trim labels
			w = 2 * maxDepth;
			// to do
			cout << "Need to shorten labels..." << endl;
		}
	}
	if (diff < 0)
	{
		labelSpace += (2 * fontHeight); // ensure we have space in small trees 
	}

	GRect r (0, 0, w + labelSpace, h);	// rectangle in which to draw tree
	// This is a hack. Inset tree to allow space for labels. Will
	// need to actually calculate this at some point
	r.Inset(fontHeight,fontHeight);
	r.SetRight (w);

	// OK, now draw the tree topology
	TreeDrawer *td;
	switch (treestyle)
	{
		case 1:
			td = new TreeDrawer (&t);
			break;
		case 2:
			td = new RectangleTreeDrawer (&t);
			break;
		case 3:
			if (t.GetHasEdgeLengths())
				td = new PhylogramDrawer (&t);
			else
				td = new RectangleTreeDrawer (&t);
			break;			
		default:
			td = new TreeDrawer (&t);
			break;
	}
	td->SetDrawLeafLabels(true);
	td->SetDrawInternalLabels(false);
	td->SetRect (r.GetLeft(), r.GetTop(), r.GetRight(), r.GetBottom());
	td->CalcCoordinates();
	
	// At this point we have a tree with coordinates
	
	// What internal labels do we want to draw?
	make_internal_list(t, td, fontHeight);

	// draw tree in slices
	int sliceHeight = 256; // thumbnails
	int numSlices = h / sliceHeight + 1;
	int hTotal = 0;
	
	for (int slice = 0; slice < numSlices; slice++)
	{
		int thisSliceHeight = sliceHeight;
		hTotal += sliceHeight;
		if (hTotal > h)
		{
			thisSliceHeight = h % sliceHeight;
		}
		// Create clipping rect and offset it to current
		// slice
		GRect clip (0, 0, w + labelSpace, thisSliceHeight);
		GRect display = clip;
		
		clip.Offset(0, slice * sliceHeight);
		
		// Display rect is complete extent of tree drawing
		GRect r (0, 0, w + labelSpace, h);

		Port = new MagickPort();
		Port->SetDisplayRect (display);	
		Port->SetClipRect(clip);		
		
		char sliceName[256];
		sprintf (sliceName, "%s.%03d.png", base_file_name, slice);
		
		char s[256];
		strcpy (s, output_path);
		strcat (s, sliceName);
			
		Port->StartPicture (s);
		
		image_files += "<img style=\"display:block;\" src=\"";
		image_files += base_url + "/" + output_url;
		image_files += sliceName;
		image_files += "\" />\n";
		
		
		// True Type monospace font
		GBaseFont fo;						
		fo.SetName ("Clarity");
//		fo.SetName ("@CLARITY_.TTF");
//		fo.SetName ("@ProggyTinySZ.TTF");
		Port->SetCurrentFont (fo);
		
		// Internal nodes (to do)
		if (showInternals)
		{
			draw_internals(td);
		}
		
		// Draw tree
		Port->SetFillColour(GBaseColour(0,0,0));
		td->Draw();
		
		Port->EndPicture ();
		delete Port;
		Port = NULL;
		
	}		
	
	//----------------------------------------------------------------------
	{
		// Output Javascript for interactions
		// Note that this uses td from above because we
		// will output dimensions from drawing the big tree.		
		strcpy (js_file_name, base_file_name);
		strcat (js_file_name, ".js");
		
		strcpy (file_name, output_path);
		strcat (file_name, js_file_name);
		
		
		ofstream js(file_name);
		{
			NodePtr left;
			NodePtr right;

			t.GetRoot()->GetSpan(left, right);

			point L, R;
			L = td->GetCoordinates(left);
			R = td->GetCoordinates(right);
			
			js << "leafGap = " << (R.y - L.y)/(double)(t.GetNumLeaves() - 1) << ";" << endl;
		}
		js << "leafX = " << w << ";" << endl;
		js << "treeWidth = " << (w + labelSpace) << ";" << endl;
		js << "imageHeight =" << h << ";" << endl;
		
		float ratio = (float)height/(float)h;
		float thumb = (float)height * ratio;

		js << "floatThumbHeight = " << thumb << ";" << endl;

		std::stack < NodePtr, std::vector<NodePtr> > stk;
		
		js << "var states = new Array (" << endl;
		int count = 0;
		Node *q = t.GetRoot();
		while (q)
		{
			if (q->GetChild()) 
			{
				stk.push(q);
				q = q->GetChild();
			}
			else
			{	
				while (!stk.empty() && (q->GetSibling() == NULL))
				{
					// going back down the tree
					q = stk.top();
					stk.pop();
				}
				if (stk.empty())
					q = NULL;
				else
				{
					q = q->GetSibling();
				}
			}
			
			if (q)
			{
				if (q->IsLeaf())
				{
					if (count > 0) 
					{
						js << "," << endl;
					}
					count++;
					js << "\"" << q->GetLabel() << "\"";
				}
			}
		}
		js << ");" << endl;
		js.close();
	}
	delete td; // we are down with big tree drawer
							
	
	//-----------------------------------------------------------------------
	
	
	
	
	if (h > height)
//	if (numSlices > 1)
	{
		// Tree needs a thumbnail
		// Make a thumbnail that user will user to navigate by. This is
		// 100 pixels wide, user-defined height (default = 400), and has 
		// no leaf labels.
		
		strcpy (thumbnail_file_name, base_file_name);
		strcat (thumbnail_file_name, "-thumbnail.png");
		
		strcpy (file_name, output_path);
		strcat (file_name, thumbnail_file_name);
		
		Port = new MagickPort();

		GRect r (0, 0, 100, height);					

		// Set up the graphics port
		Port->SetDisplayRect (r);
		Port->StartPicture (file_name);
		GBaseFont fo;				// default font
		fo.SetName ("@CLARITY_.TTF");
		Port->SetCurrentFont (fo);

		// OK, now draw the tree topology
		TreeDrawer *td;
		switch (treestyle)
		{
			case 1:
				td = new TreeDrawer (&t);
				break;
			case 2:
				td = new RectangleTreeDrawer (&t);
				break;
			case 3:
				if (t.GetHasEdgeLengths())
					td = new PhylogramDrawer (&t);
				else
					td = new RectangleTreeDrawer (&t);
				break;			
			default:
				td = new TreeDrawer (&t);
				break;
		}
		// Suppress drawing leaf labels, as we handle this separately
		td->SetDrawLeafLabels(false);
		td->SetDrawInternalLabels(false);
		td->SetRect (r.GetLeft(), r.GetTop(), r.GetRight(), r.GetBottom());
		td->SetFont(fo);
		td->CalcCoordinates();

		// Internals
		if (showInternals)
		{
			draw_internals(td, false);
		}
		
		// Draw tree
		td->Draw();
		
		delete td;
		
		Port->EndPicture ();

		delete Port;
		Port = NULL;
	}
	
	// Output widget
	std:string html;
	
	if (h > height)
//	if (numSlices > 1)
	{
		// Big tree
		html =
"<script type=\"text/javascript\" src=\"";
		html += base_url + "/";
		html += output_url;
		html += js_file_name;
		html +=
"\"></script>\n"
"\n"
"<!-- Add handler for mouse wheel -->\n"
"<script type=\"text/javascript\">\n"
"	if (window.addEventListener)\n"
"	        /** DOMMouseScroll is for mozilla. */\n"
"	        window.addEventListener('DOMMouseScroll', wheel, false);\n"
"	/** IE/Opera. */\n"
"	window.onmousewheel = document.onmousewheel = wheel;\n"
"</script>\n"
"<!-- create the tree viewer -->\n" 
"<div style=\"position:absolute;left:0px;top:0px;\">\n" 
"	\n" 
"	<div id=\"tvwTreeWidget\">\n" 
"	\n" 
"		<!-- tool bar -->\n" 
"		<div id=\"tvwTreeTools\">\n" 
"			<!--<span id=\"tvwFind\">Find	</span> -->\n" 
"			<input id =\"tvwLeafOne\" type=\"text\" onkeyup=\"autocomplete.change(this, event, states)\" />\n" 
"           <button id=\"tvwGo\" type=\"button\" onclick=\"showLabel();\"/>Jump to</button>\n" 
"			<script type=\"text/javascript\">\n" 
"				autocomplete.initialize();\n" 
"			</script>\n" 
"		</div>\n" 
"		\n" 
"		<!-- Box to include scroller and big tree -->\n"
"		<div id=\"tvwBox\">\n"
"\n"
"		<!-- scroller and tree thumbnail -->\n" 
"		<div id=\"tvwTreeScroller\">\n" 
"			<div id=\"tvwThumbTrack\"></div>\n" 
"			<div id=\"tvwThumbnail\" style=\"background-image:url(";
html += output_url;
html += thumbnail_file_name;
html += ");\"></div> \n" 
"			<div id=\"tvwTrack1\"></div>\n" 
"			<div id=\"tvwTrack2\"></div>\n" 
"			<div id=\"tvwThumb\" onmousedown=\"dragStart(event, 'tvwThumb');captureThumb(event);\">\n" 
"				<div id =\"tvwThumbHandle\"></div>\n" 
"			</div>\n" 
"		</div>\n" 
"\n" 
"		<!-- Marker for when we search for a name -->\n" 
"		<div id=\"tvwMarker1\"></div>\n"
"\n" 
"		<!-- big tree -->\n" 
"		<div id=\"tvwViewer\" class=\"tvwViewer\" >\n" 
"			<div id=\"tvwWell\" class=\"tvwWell\">\n" 
"				<!-- image slices -->\n";
		html += image_files;
		html +=
"				<div id=\"tvwLabelOne\"></div>\n" 
"			</div> \n" 
"			<!-- surface user drags to move big tree -->\n" 
"			<div class=\"tvwSurface\" id=\"tvwSurface\" onmousedown=\"dragStart(event, 'tvwWell');captureSurface(event);\"></div> 	\n" 
"			<!-- user clicks here for information on taxon -->\n" 
"			<div class=\"tvwTaxa\" id=\"tvwTaxa\" onmousedown=\"doTaxa(this, event);\"></div> 		\n" 
"		</div>\n" 
"		</div> <!-- close Box -->\n" 
"\n" 
"	</div>\n" 
"\n" 
"</div>\n" 
"	\n" 
"<!-- tree specific adjustments to make once we've loaded widget -->\n" 
"<script type=\"text/javascript\">\n" 
"	function tvwAdjustViewer()\n"
"	{"
"		var t = document.getElementById('tvwThumb');\n" 
"		t.style.height = floatThumbHeight + 'px';\n" 
"\n" 
"		t = document.getElementById('tvwThumbHandle');\n" 
"		t.style.height = floatThumbHeight + 'px';\n" 
"\n" 
"		t = document.getElementById('tvwTreeScroller');\n" 
"\n" 
"\n" 
"		t2 = document.getElementById('tvwTrack2');\n" 
"		t2.style.top = (floatThumbHeight + 1) + 'px';\n" 
"		t2.style.height = ";

char int_buf[32];
sprintf(int_buf,"%d",height);
html += int_buf;
html += " - floatThumbHeight + 'px';\n" 
"		// Adjust \n" 
"		s = document.getElementById('tvwSurface');\n" 
"		s.style.width = leafX + 'px';\n" 
"\n" 
"		t = document.getElementById('tvwTaxa');\n" 
"		t.style.left = leafX + 'px';\n" 
"		t.style.width = (";
sprintf(int_buf,"%d",width);
html += int_buf;
html += " - leafX)  + 'px';\n" 
"		t.style.height = imageHeight + 'px';\n"
"	}\n"
"\n" 
"</script>\n" 
"\n" 
"<!-- end of widget -->\n";
	}
	else
	{
		// Small tree
		html =
"<script type=\"text/javascript\" src=\"";
		html += base_url + "/";
		html += output_url;
		html += js_file_name;
		html +=
"\"></script>\n"
"\n"
"<!-- create the tree viewer -->\n" 
"<div style=\"position:absolute;left:0px;top:0px;\">\n" 
"	\n" 
"	<div id=\"tvwWidget\">\n"
"	\n" 
"		<!-- tool bar -->\n" 
"		<div id=\"tvwTreeTools\"></div>\n" 
"		<div id=\"tvwBox\" style=\"border-left:1px solid rgb(163,163,163);\">\n"
"			<div id=\"tvwViewer\" class=\"tvwViewer\">\n"
"				<div id=\"tvwWell\" class=\"tvwWell\">\n"
"					<!-- 1 tree -->\n"
"					<div style=\"position:absolute;top:";

// Center image in DIV

int space = (height - h)/2;
char int_buf[32];
sprintf(int_buf,"%d",space);
html += int_buf;
html += "px; left: 0px;\">\n";
		html += image_files;
		html +=
"						<!-- user clicks here for information on taxon -->\n"
"						<div class=\"tvwTaxa\"  id=\"tvwTaxa\" style=\"position:absolute;top:0px; left: ";
sprintf(int_buf,"%d",w);
html += int_buf;
html +=
"px;\"\n"
"					onmousedown=\"doTaxa(this, event);\"></div> \n"
"					</div>\n"
"					<div id=\"tvwLabelOne\"></div>\n"
"				</div> \n"
"			</div>		\n"
"		</div>\n"
"	</div>\n"
"</div>\n"
"<!-- end of widget -->\n"
"<script type=\"text/javascript\">\n"
"	function tvwAdjustViewer() {}\n"
"</script>\n";
		
		
	}
	//cout << html;
	
	// Javascript packaging
	string searchString( "\"" ); 
	//string replaceString( "\\\\\\\"" );
	string replaceString( "\\\"" );
	
	
	size_t spos = 0;
    while ( (spos = html.find(searchString, spos)) != string::npos ) 
	{
       html.replace( spos, searchString.size(), replaceString );
        spos += replaceString.size();
    }
	
	searchString = "\n";
	replaceString = "\\n";
	
	while ( (spos = html.find(searchString, spos)) != string::npos ) 
	{
        html.replace( spos, searchString.size(), replaceString );
        spos += replaceString.size();
    }
	
	
	char package_file_name[256];
	strcpy (package_file_name, output_path);
	strcat (package_file_name, base_file_name);
	strcat (package_file_name, ".widget.js");

	ofstream package(package_file_name);

	package << "document.write(\"" << html << "\");";
	package.close();
	
	
	char leaf_file_name[256];
	strcpy (leaf_file_name, output_path);
	strcat (leaf_file_name, base_file_name);
	strcat (leaf_file_name, ".txt");

	ofstream leaf_names(leaf_file_name);

	for (int i = 0; i < t.GetNumLeaves();  i++)
	{
		leaf_names <<  t[i]->GetLabel() << endl;
	}
	leaf_names.close();
	
	return 0;
}
